package com.bsoft.advance.server.transport;

import com.alibaba.fastjson.JSON;
import com.bsoft.advance.core.common.RpcRequest;
import com.bsoft.advance.core.common.RpcResponse;
import com.bsoft.advance.core.protocol.MessageHeader;
import com.bsoft.advance.core.protocol.MessageProtocol;
import com.bsoft.advance.core.protocol.MsgStatus;
import com.bsoft.advance.core.protocol.MsgType;
import com.bsoft.advance.server.cache.RpcServiceCache;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

/**
 * 处理客户端发送来的请求
 */
@Slf4j
public class RpcRequestHandler extends SimpleChannelInboundHandler<MessageProtocol<RpcRequest>> {

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            // 读空闲超时事件
            if (IdleState.READER_IDLE == state) {
                log.info("client [{}] 已经 60s 没来找我了！我要跟他断绝关系。。。", ctx.channel().remoteAddress().toString().substring(1));
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("client [{}] is connected!", ctx.channel().remoteAddress().toString().substring(1));
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("client [{}] is disconnected!", ctx.channel().remoteAddress().toString().substring(1));
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageProtocol<RpcRequest> protocol) throws Exception {
        log.info("client [{}] is posted!", ctx.channel().remoteAddress().toString().substring(1));
        // 拿到客户端发送来的消息，并进行路由到对应的服务
        MessageProtocol<RpcResponse> responseProtocol = new MessageProtocol<>();
        RpcResponse response = new RpcResponse();
        MessageHeader header = protocol.getHeader();
        switch (MsgType.findByType(header.getMsgType())) {
            case REQUEST:
                header.setMsgType(MsgType.RESPONSE.getType());
                header.setStatus(MsgStatus.SUCCESS.getCode());
                // 执行请求
                Object result = null;
                try {
                    log.info("request protocol: {}", JSON.toJSONString(protocol));
                    result = handler(protocol.getBody());
                    // 组装响应
                    response.setData(result);
                } catch (Exception e) {
                    e.printStackTrace();
                    header.setStatus(MsgStatus.SUCCESS.getCode());
                    response.setErrMsg(e.getMessage());
                }
                responseProtocol.setHeader(header);
                responseProtocol.setBody(response);
                // 发送结果
                ctx.channel().writeAndFlush(responseProtocol);
                break;
            case RESPONSE:
                break;
            case HEARTBEAT_REQUEST:
            case HEARTBEAT_RESPONSE:
                // 处理心跳
                log.info("client [{}] is heartbeat : {}", ctx.channel().remoteAddress().toString().substring(1), protocol.getBody().getHeartbeat());
                invokeHeartBeat(ctx, responseProtocol);
                break;
            default:
                break;
        }
    }

    /**
     * 反射找到对应的类，并且执行获取结果
     */
    private Object handler(RpcRequest request) throws Exception {

        // 从缓存中找到目标实现类对象
        Object service = RpcServiceCache.getService(request.getServiceName());
        if (service == null) {
            throw new IllegalStateException("服务不存在");
        }
        // 反射调用接口
        Method method = ReflectionUtils.findMethod(service.getClass(), request.getMethodName(), request.getParameterTypes());
        return ReflectionUtils.invokeMethod(method, service, request.getParameters());
    }

    /**
     * 处理心跳请求
     */
    private void invokeHeartBeat(ChannelHandlerContext ctx, MessageProtocol<RpcResponse> responseProtocol) {
        responseProtocol.setBody(RpcResponse.buildHeartBeat());
        responseProtocol.setHeader(MessageHeader.buildHeartBeat(MsgType.HEARTBEAT_RESPONSE));
        ctx.channel().writeAndFlush(responseProtocol);
    }

}
